package com.iring.service.common.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.iring.domain.config.PayConfig;
import com.iring.domain.config.prop.AliPayProperties;
import com.iring.domain.config.prop.PayProperties;
import com.iring.dao.common.PayListDao;
import com.iring.dao.common.PayOrderDao;
import com.iring.domain.common.PayList;
import com.iring.domain.common.PayOrder;
import com.iring.domain.common.User;
import com.iring.domain.config.PayEnum;
import com.iring.domain.config.PayStatusEnum;
import com.iring.domain.pay.check.AlipayCheck;
import com.iring.domain.pay.check.PayCheck;
import com.iring.domain.pay.check.PaypalCheck;
import com.iring.domain.pay.info.AliPayInfo;
import com.iring.domain.pay.info.PayPalInfo;
import com.iring.domain.pay.res.AliPayRes;
import com.iring.domain.pay.res.PaypalRes;
import com.iring.exception.ParamInvalidException;
import com.iring.exception.config.ErrorEnum;
import com.iring.service.common.OrderService;
import com.iring.service.common.PayReqService;
import com.iring.service.pay.PayService;
import com.iring.util.common.CommonUtil;
import com.iring.vo.pay.PayBackVO;
import com.iring.vo.pay.PayVO;


/**
 * @author wanggan
 */
@Service
public class PayReqServiceImpl implements PayReqService {

    private static final Logger logger = LoggerFactory.getLogger(PayReqServiceImpl.class);

    @Resource(name = "paypal")
    PayService<PayPalInfo, PaypalRes,PaypalCheck> paypalService;

    @Resource(name = "alipay")
    PayService<AliPayInfo,AliPayRes,AlipayCheck> alipayService;

    @Resource(name = "wechatpay")
    PayService wechatpayService;

    @Autowired
    OrderService orderService;

    @Autowired
    PayProperties payProperties;

    @Autowired
    PayListDao payListDao;

    @Autowired
    PayOrderDao payOrderDao;

    @Autowired
    AliPayProperties aliPayProperties;

    @Autowired
    CommonUtil commonUtil;


    @Override
    public Boolean cancelOrder(String orderid, String username) {
        if(null == orderid || orderid.trim().equals("")){
            throw new ParamInvalidException("orderid is null");
        }
        //TODO 查找订单信息
        List<String> list = new ArrayList<>();
        list.add(PayConfig.ORDER_CREATED);
        list.add(PayConfig.WAIT_BUYER_PAY);
        PayOrder payOrder = payOrderDao.findByUsernameAndOrderIdAndPayStatusIn(username,orderid,list);
        if(payOrder instanceof PayOrder){
            String payType = payOrder.getOrderType();
            String tradeNo = payOrder.getTradeNo();

            if (PayConfig.PAYPAL.equals(payType)) {
                //TODO 取消paypal
                PayPalInfo payPalInfo = new PayPalInfo();
                payPalInfo.setOrderId(tradeNo);
                paypalService.cancelPay(payPalInfo);
                payOrder.setPayStatus(PayConfig.ORDER_FAILED);
            } else if (PayConfig.ALIPAY.equals(payType)) {
                //TODO 取消alipay的
                AliPayInfo aliPayInfo = new AliPayInfo();
                aliPayInfo.setOut_trade_no(orderid);
                alipayService.cancelPay(aliPayInfo);
                payOrder.setPayStatus(PayConfig.TRADE_CLOSED);
            } else {
                //TODO 其他的操作
            }

            payOrder.setOrderCloseTime(null);

            payOrder.setOrderStatus(PayStatusEnum.PAY_CLOSED.getValue());
            payOrderDao.save(payOrder);
            return Boolean.TRUE;
        }else{
            throw new ParamInvalidException(ErrorEnum.CANCEL_ORDER_FAILED);
        }
    }

    @Override
    public PaypalCheck checkPaypal(PaypalCheck paypalCheck) {
        paypalCheck = paypalService.checkPay(paypalCheck);
        if (paypalCheck.getPayResult()) {
            String tradeNo = paypalCheck.getTradeNo();
            String payerid = paypalCheck.getPayerId();
            String paystatus = paypalCheck.getPayStatus();
            PayOrder payOrder = payOrderDao.findByTradeNo(tradeNo);
            String orderid = payOrder.getOrderId();
            User user = orderService.updateByOrderid(orderid,tradeNo,paystatus,payerid);
            if (user instanceof User) {
                paypalCheck.setOrderId(orderid);
                paypalCheck.setUsername(user.getUsername());
                paypalCheck.setRestAmounts(user.getRestAmounts());
            }
        }
        return  paypalCheck;
    }

    @Override
    public PayCheck checkAlipay(Map<String, String> paramsMap) {

        PayCheck basePay = new PayCheck();
        boolean signVerified; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(paramsMap, aliPayProperties.getAlipayPubKey(), "UTF-8", aliPayProperties.getSignType());
            if(signVerified){
                // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，
                // 校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure

                //1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
                // 2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
                // 3、校验通知中的seller_id（或者seller_email)
                // 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email），
                // 4、验证app_id是否为该商户本身


                String out_trade_no = paramsMap.get("out_trade_no");
                String tadeNo = paramsMap.get("trade_no");
                Double totalAmount = Double.valueOf(paramsMap.get("total_amount"));
                String sellerId = paramsMap.get("seller_id");
                String appId = paramsMap.get("app_id");
                String payStatus = paramsMap.get("trade_status");
                String payerId = paramsMap.get("buyer_id");

                // TODO 校验订单号，对于我们来说是订单号
                PayOrder payOrder = payOrderDao.findByOrderId(out_trade_no);
                Boolean isOrder = false;
                if (payOrder != null){
                    isOrder = true;
                }

                //TODO检查金额
                Boolean isAmount = false;
                if(payOrder.getRealchargeAmouts().compareTo(totalAmount)==0){
                    isAmount = true;
                }

                Boolean isSeller  = false;
                if(aliPayProperties.getSellerId().equals(sellerId)){
                    isSeller = true;
                }

                Boolean isAppid = false;
                if(aliPayProperties.getAppid().equals(appId)){
                    isAppid = true;
                }

                if(!isOrder || !isAmount || !isSeller || !isAppid){
                    return null;
                }

                User user = orderService.updateByOrderid(out_trade_no,tadeNo,payStatus,payerId);
                if (user != null) {
                    basePay.setOrderId(out_trade_no);
                    basePay.setUsername(user.getUsername());
                    basePay.setRestAmounts(user.getRestAmounts());
                }
                return basePay;
            }else{
                // TODO 验签失败则记录异常日志，并在response中返回failure.
                logger.info("check alipay sign failed..");
            }
        } catch (AlipayApiException e) {
            logger.info("check alipay order failed={}",e);
        }
        return null;

    }


    @Override
    public PayBackVO addAlipay(PayVO payVO, String username) {
        checkUnfinishOrder(username);
        String orderid = commonUtil.getOrderid();
        Double optAmounts = payVO.getOptamounts();
        Double realAmounts = getDiscountAmounts(optAmounts);

        PayOrder payOrder = new PayOrder();
        payOrder.setUsername(username);
        payOrder.setOrderId(orderid);
        payOrder.setOptAmounts(optAmounts);
        payOrder.setRealchargeAmouts(realAmounts);
        payOrder.setOrderStatus(PayConfig.WAIT_USER_PAY);
        payOrder.setPayStatus(PayConfig.WAIT_BUYER_PAY);
        payOrder.setOrderType(PayConfig.ALIPAY);
        payOrder.setOrderCreateTime(null);
        payOrderDao.save(payOrder);
        PayBackVO payBackVO = new PayBackVO();
        payBackVO.setOrderid(orderid);
        return payBackVO;
    }

    @Override
    public AliPayRes addAlipayOrder(String orderid, String username) {

        PayOrder payOrder = payOrderDao.findByOrderId(orderid);
        if(null == payOrder){
            throw new ParamInvalidException("invalid orderid");
        }

        Double optAmounts = payOrder.getOptAmounts();

        Double realAmounts = payOrder.getRealchargeAmouts();
        AliPayInfo aliPayInfo = new AliPayInfo();
        aliPayInfo.setOut_trade_no(orderid);
        aliPayInfo.setTotal_amount(String.format("%.2f",realAmounts));
        AliPayRes aliPayRes = alipayService.createPay(aliPayInfo);
        String payStatus = PayConfig.WAIT_BUYER_PAY;
        String orderHref = aliPayRes.getOrderHref();
        String invoiceNumber = "";
        String tradeNo = aliPayRes.getTradeNo();
        payOrder = createLocalPayOrder(username,orderid,tradeNo,optAmounts,realAmounts, PayEnum.ALIPAY,payStatus,orderHref,invoiceNumber);
        if(payOrder instanceof  PayOrder){
            return aliPayRes;
        }
        return null;

    }

    @Override
    public AliPayRes repayAlipayOrder(String orderid, String username) {
        if(null == orderid || orderid.trim().equals("")){
            throw new ParamInvalidException("orderid is null");
        }
        //TODO 查找订单信息
        List<String> list = new ArrayList<>();
        list.add(PayConfig.WAIT_USER_PAY);
        PayOrder payOrder = payOrderDao.findByUsernameAndOrderIdAndOrderStatusIn(username,orderid,list);
        if(payOrder instanceof PayOrder){
            //TODO先进行取消订单，再进行支付
            String url = payOrder.getOrderHref();
            AliPayRes aliPayRes = new AliPayRes();
            aliPayRes.setOrderHref(url);
            return aliPayRes;
        }else{
            throw new ParamInvalidException("invalid alipay order");
        }
    }

    @Override
    public PayBackVO repayPaypalOrder(String orderid, String username) {
        if (null == orderid || orderid.trim().equals("")) {
            throw new ParamInvalidException("orderid is null");
        }
        List<String> list = new ArrayList<>();
        list.add(PayConfig.ORDER_CREATED);
        PayOrder payOrder = payOrderDao.findByUsernameAndOrderIdAndPayStatusIn(username, orderid, list);
        if (payOrder instanceof PayOrder) {
            String url = payOrder.getOrderHref();
            return new PayBackVO(orderid, url);
        }
        throw new ParamInvalidException("invalid paypal order");
    }

    @Override
    public PaypalRes addPaypalOrder(PayVO payVO, String username) {
        checkUnfinishOrder(username);
        //获取需要进行操作的金额
        Double optAmounts = payVO.getOptamounts();
        //获取打折后的金额
        Double realAmounts = getDiscountAmounts(optAmounts);

        PayPalInfo payPalInfo = new PayPalInfo(realAmounts);
        //生成订单id
        String orderid = commonUtil.getOrderid();
        //设置订单信息
        payPalInfo.setTotal(realAmounts);

        PaypalRes paypalRes = paypalService.createPay(payPalInfo);

        String tradeNo = paypalRes.getTradeNo();
        String payStatus = paypalRes.getState();
        String orderHref = paypalRes.getOrderHref();
        String invoiceNumber = paypalRes.getInvoiceNumber();

        PayOrder payOrder =  createLocalPayOrder(username,orderid,tradeNo,optAmounts,realAmounts,PayEnum.PAYPAL,payStatus,orderHref,invoiceNumber);
        if(payOrder instanceof PayOrder){
            paypalRes.setOrderid(orderid);
        }
        return paypalRes;
    }

    /**
     * 检查未完成的订单
     *
     * @param username
     *          用户名
     * @return  是否有未完成订单
     */
    private Boolean checkUnfinishOrder(String username){
        List<String> list = new ArrayList<>();
        list.add(PayConfig.ORDER_CREATED);
        list.add(PayConfig.WAIT_BUYER_PAY);



        List<String> oList = new ArrayList<>();
        oList.add(PayConfig.WAIT_USER_PAY);


        List<PayOrder> orderList = payOrderDao.findByUsernameAndPayStatusInAndOrderStatusIn(username,list,oList);
        Integer limitCount = payProperties.getLimitCount();
        if(orderList.size() >= limitCount){
            throw new ParamInvalidException("410","uncomplete order more than limit "+limitCount);
        }
        return Boolean.TRUE;
    }

    private Double getDiscountAmounts(Double optAmounts){
        PayList pay = payListDao.showOtherPayInfo(optAmounts);
        Assert.notNull(pay, "pay info must not be null");
        Double realAmounts = pay.getDiscount();
        return realAmounts;
    }


    /**
     * 创建本地订单记录
     * @param username
     *          用户名
     * @param orderid
     *          订单id
     * @param tradeNo
     *         支付平台交易号
     * @param optAmounts
     *         操作金额
     * @param realAmounts
     *          实付金额
     * @param payType
     *          支付类型
     * @param payStatus
     *          支付状态
     * @param orderHref
     *          支付链接
     * @param invoiceNumber
     *          发票单号
     * @return 创建好的订单信息
     */
    private PayOrder createLocalPayOrder(String username,String orderid,String tradeNo,
                                     Double optAmounts,Double realAmounts,PayEnum payType,
                                     String payStatus,String orderHref,String invoiceNumber){

        PayOrder payOrder1 = payOrderDao.findByOrderId(orderid);
        if(payOrder1 instanceof PayOrder){
            payOrder1.setUsername(username);
            payOrder1.setTradeNo(tradeNo);
            payOrder1.setOrderType(payType.getValue());
            payOrder1.setOrderStatus(PayStatusEnum.WAIT_USER_PAY.getValue());
            payOrder1.setPayStatus(payStatus);
            payOrder1.setOrderHref(orderHref);
            payOrder1.setOrderCreateTime(null);
            payOrder1.setInvoiceNumber(invoiceNumber);
            return orderService.save(payOrder1);
        }else {
            PayOrder payOrder = new PayOrder();
            payOrder.setUsername(username);
            payOrder.setOrderId(orderid);
            payOrder.setTradeNo(tradeNo);
            payOrder.setOptAmounts(optAmounts);
            payOrder.setRealchargeAmouts(realAmounts);
            payOrder.setOrderType(payType.getValue());
            payOrder.setOrderStatus(PayStatusEnum.WAIT_USER_PAY.getValue());
            payOrder.setPayStatus(payStatus);
            payOrder.setOrderHref(orderHref);
            payOrder.setOrderCreateTime(null);
            payOrder.setInvoiceNumber(invoiceNumber);
            // 生成订单
            return orderService.save(payOrder);
        }

    }

}
